#pragma once
#include<sys/socket.h>
#include<sys/types.h>
#include<functional>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<strings.h>
#include"Log.hpp"
#include"InetAddr.hpp"

using namespace LogModule;
using namespace InetAddrModule;
const int defaultfd = -1;
using func_t = std::function<std::string(const std::string&, InetAddr&)>;

class UdpServer
{
public:
    UdpServer(uint16_t port, func_t func)
        : _socketfd(defaultfd),_port(port),_isrunning(false)
        ,_func(func)
    {
    }

    void Init()
    {
        // step1 创建套接字
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket create error!";
            exit(1);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd : " << _socketfd;
        //step2 绑定socket信息，ip和端口号,
        //2.1 填充struct sockadd_in 结构体
        struct sockaddr_in local;
        bzero(&local, sizeof(local)); //清零
        local.sin_family = AF_INET;
        //local.sin_addr.s_addr = inet_addr(_ip.c_str()); // TODO
        local.sin_addr.s_addr = INADDR_ANY; //服务端做任意地址绑定，方便接收客户端发来的消息
        local.sin_port = htons(_port); //主机转网络序列
        //2.2 服务器显示bind：因为IP和端口号必须是众所周知且不能轻易改变
        int n = bind(_socketfd, (struct sockaddr*) &local, sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(2);
        }
        LOG(LogLevel::INFO) << "bind success, sockfd : " << _socketfd;
    }

    void Start()
    {
       _isrunning = true;
       while(_isrunning)
       {
          char buffer[1024];
          struct sockaddr_in peer;
          socklen_t len = sizeof(peer);
          // 1、收消息
          // 2、处理数据
          ssize_t s =recvfrom(_socketfd, buffer, sizeof(buffer) - 1, 0, (struct  sockaddr*) &peer, &len);
          if(s > 0)
          {
              InetAddr client(peer);
              buffer[s] = '\0';
              //收到的内容当做英语单词
              std::string result = _func(buffer, client);
            //   std::string result = _func(buffer);
            //   // 3、发消息:包括消息内容和谁发的
             sendto(_socketfd, result.c_str(), result.size(), 0, (struct sockaddr *)&peer, len);
          }
          
       }
    }

    ~UdpServer() {}

private:
    //std::string _ip; // 字符串风格，点分十进制 服务器端不需要ip地址
    int _socketfd;
    uint16_t _port;
    bool _isrunning;
    func_t _func;//服务器的回调函数，用来进行对数据进行处理
};
